package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.domain.po.PointsBoard;
import com.tianji.learning.domain.query.PointsBoardQuery;
import com.tianji.learning.domain.vo.PointsBoardItemVO;
import com.tianji.learning.domain.vo.PointsBoardVO;
import com.tianji.learning.mapper.PointsBoardMapper;
import com.tianji.learning.service.IPointsBoardService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 学霸天梯榜 服务实现类
 * </p>
 *
 * @author llt
 * @since 2024-07-28
 */
@Service
@RequiredArgsConstructor
public class PointsBoardServiceImpl extends ServiceImpl<PointsBoardMapper, PointsBoard> implements IPointsBoardService {

    private final StringRedisTemplate redisTemplate;

    private final UserClient userClient;

    @Override
    public PointsBoardVO queryPointsBoardList(PointsBoardQuery query) {

        LocalDate now1 = LocalDate.now();
        String format = now1.format(DateTimeFormatter.ofPattern("yyyyMM"));
        String key = RedisConstants.POINTS_BOARD_KEY_PREFIX + format;

        // 1. 获取当前登陆 id
        Long userId = UserContext.getUser();

        // 2. 判断查当前赛季还是历史赛季
        boolean isCurrent = query.getSeason() == null || query.getSeason() == 0; // true 表示当前赛季

        // 3. 查询我的排名和积分
        PointsBoard board = isCurrent ? queryMyCurrentBoard(key) : queryMyHistoryBoard(query.getSeason());

        // 4. 查列表(其他人的积分)
        List<PointsBoard> list = isCurrent ? queryCurrentBoard(key, query.getPageNo(), query.getPageSize()) : queryHistoryBoard(query);

        // 5. 封装用户id集合远程调用用户服务 获取用户信息 并转map
        Set<Long> uids = list.stream().map(PointsBoard::getUserId).collect(Collectors.toSet());

        List<UserDTO> userDTOS = userClient.queryUserByIds(uids);
        if (CollUtils.isEmpty(userDTOS)) {
            throw new BizIllegalException("用户不存在");
        }

        // 转map, key是用户id value 是用户名称
        Map<Long, String> userDTOMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, c -> c.getName()));

        // 6. 封装 vo 返回
        PointsBoardVO vo = new PointsBoardVO();
        vo.setRank(board.getRank()); // 我的
        vo.setPoints(board.getRank()); // 我的

        List<PointsBoardItemVO> volist = new ArrayList<>();
        for (PointsBoard pointsBoard : list) {
            PointsBoardItemVO itemVo = new PointsBoardItemVO();
            itemVo.setName(userDTOMap.get(pointsBoard.getUserId()));
            itemVo.setPoints(pointsBoard.getPoints());
            itemVo.setRank(pointsBoard.getRank());
        }

        vo.setBoardList(volist);

        return null;
    }

    // 查榜上历史赛季(db)
    private List<PointsBoard> queryHistoryBoard(PointsBoardQuery query) {
        return null;
    }

    // 查榜上当前赛季(redis)
    public List<PointsBoard> queryCurrentBoard(String key, Integer pageNo, Integer pageSize) {
        // 1. 计算 start 和 stop
        int start = (pageNo - 1) * pageSize;
        int end = start + pageSize - 1;

        // 2. 利用 zrevange 按分数降序(分页查询)
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
        if (CollUtils.isEmpty(typedTuples)) {
            return CollUtils.emptyList();
        }

        // 3. 封装结果返回
        int rank = start + 1;
        List<PointsBoard> list = new ArrayList<>();

        for (ZSetOperations.TypedTuple<String> typedTuple : typedTuples) {
            String value = typedTuple.getValue();
            Double score = typedTuple.getScore();
            if (StringUtils.isBlank(value) || score == null) {
                continue;
            }
            PointsBoard board = new PointsBoard();
            board.setUserId(Long.valueOf(value));
            board.setPoints(score.intValue());
            board.setRank(rank++);

            list.add(board);
        }

        return list;
    }

    // 历史赛季我的积分和排名(db)
    private PointsBoard queryMyHistoryBoard(Long season) {
        return null;
    }

    // 当前赛季积分和排名(redis)
    private PointsBoard queryMyCurrentBoard(String key) {
        Long userId = UserContext.getUser();

        // 获取积分
        Double score = redisTemplate.opsForZSet().score(key, userId.toString());

        // 获取排名
        Long rank = redisTemplate.opsForZSet().reverseRank(key, userId.toString());

        PointsBoard board = new PointsBoard();
        board.setRank(rank == null ? 0 : rank.intValue() + 1); // 下标从0开始, 要加上1
        board.setPoints(score == null ? 0 : score.intValue());

        return board;
    }
}
